/****************************************************************
*名    称:基于stm32f4的mqtt
*作    者:陈堪才
*创建日期:2021/05/22
*知 识 点:
	1.esp8266 wifi的AT指令的使用
	2.mqtt的连接、发布、订阅等	
	3.添加了cJSON
*说  明:		
	1.通过阿里云物联网平台能够获取开发板的D1、D2、D3灯和温湿度值
	2.通过阿里云物联网平台能够控制开发板的D1、D2、D3灯的亮灭
	3.D4灯用于表示当前连接服务器的状态。亮-已连接；灭-已断开
	4.按键1用于重连阿里云物联网平台
	5.按键2用于断开阿里云物联网平台
*修改日期:
	2021/05/27，增加了cJSON对阿里云物联网平台的数据解析
*****************************************************************/
#include "stm32f4xx.h"
#include "sys.h"
#include "usart.h"
#include "esp8266.h"
#include "esp8266_mqtt.h"
#include "delay.h"
#include "led.h"
#include "beep.h"
#include "dht11.h"
#include "key.h"
#include "tim.h"
#include "cjson.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


void mqtt_cjson_parse(char *pbuf)
{
	cJSON *json , *json_params, *json_id, *json_led, *json_method;
	
	char *p = pbuf;
		
	//解析数据包
	json = cJSON_Parse(p);			
	if (!json)  
	{  
		cJSON_Delete(json);
		json=NULL;		
		return;
	} 		
	
	//根据method键获取值
	json_method = cJSON_GetObjectItem(json ,"method"); 
	if(json_method->type == cJSON_String)
	{
		printf("method:%s\r\n", json_method->valuestring);  
	}	
	
	//根据id键获取值			
	json_id = cJSON_GetObjectItem(json , "id"); 
	if(json_id->type == cJSON_String)
	{
		printf("id:%s\r\n", json_id->valuestring);  
	}	
	
	//根据params键获取值
	json_params = cJSON_GetObjectItem(json , "params"); 
	if(json_params)
	{
		//根据switch_led_r键获取值
		json_led=cJSON_GetObjectItem(json_params , "switch_led_r"); 
		if(json_led->type == cJSON_Number)
		{
			PFout(9) = !json_led->valueint; 
			printf("switch_led_r:%d\r\n", json_led->valueint);  
		}
		
		//根据switch_led_g键获取值
		json_led=cJSON_GetObjectItem(json_params , "switch_led_g"); 
		if(json_led->type == cJSON_Number)
		{
			PFout(10) = !json_led->valueint; 
			printf("switch_led_g:%d\r\n", json_led->valueint);  
		}	
		
		//根据switch_led_b键获取值
		json_led=cJSON_GetObjectItem(json_params , "switch_led_b"); 
		if(json_led->type == cJSON_Number)
		{
			PEout(13) = !json_led->valueint;
			printf("switch_led_b:%d\r\n", json_led->valueint);  
		}				
	}
	cJSON_Delete(json);
	json=NULL;	
}

int main(void)
{
	uint32_t 	i=0;
	uint32_t 	delay_1ms_cnt=0;
	uint8_t		buf[5]={20,05,56,8,20};
	uint32_t	key_sta=0;
	int32_t		rt=0;

	Delay_Init();
	
	//led初始化
	led_init();
	
	//beep初始化
	beep_init();	
	
	//温湿度传感器初始化
	dht11_init();
	
	//按键检测
	key_init();
	
	//定时器初始化
	tim3_init();
	
	//串口1初始化波特率为115200bps
	usart1_init(115200);
	
	//串口延迟一会，确保芯片内部完成全部初始化,printf无乱码输出
	delay_ms(500);
	
	//打印开机信息
	printf("This is esp8266 mqtt with aliyun test by teacher.chen\r\n");

	
	while(esp8266_mqtt_init())
	{
		printf("esp8266_mqtt_init ...");
		
		delay_s(1);
	}
	
	//连接服务器状态指示灯，点亮-连接成功
	CONNECT_MQTT_LED(1);

	printf("esp8266 connect aliyun with mqtt success\r\n");	
	
	while(1)
	{
		//检查接收到数据
		if(g_esp8266_rx_end && g_esp8266_transparent_transmission_sta)
		{
#if 1		
			
			printf("g_esp8266_rx_buf:%s\n",g_esp8266_rx_buf);
			
			for(i=0;i<g_esp8266_rx_cnt;i++)
			{	
/*
由于mqtt协议发布消息数据包 = 0x30+剩余长度+01+00+Topic主题名+json内容，例如通过阿里云物联网平台发送如下			
0x30 0xE2 0x01 0x00 /thing/service/property/set{"method":"thing.service.property.set","id":"408723893","params":{"switch_led_g":1,"version":"1.0.0"}		
传给cJSON时必须全为字符串，不能有0x00，否则遇到0x00会导致直接结束cJSON的。因此需要自行查找'{'开头的json内容				
*/
				if(g_esp8266_rx_buf[i] == '{')
				{
					mqtt_cjson_parse((char *)&g_esp8266_rx_buf[i]);
					break;
				}
			}
#else
			for(i=0;i<g_esp8266_rx_cnt;i++)
			{
				//判断的关键字符是否为 1"
				//核心数据，即{"switch_led_r":1}中的“1”
				if((g_esp8266_rx_buf[i]==0x31) && (g_esp8266_rx_buf[i+1]==0x22))
				{
						//判断控制变量
						if( g_esp8266_rx_buf[i+3]=='1' )
							PFout(9)=0;//控制灯亮
						else
							PFout(9)=1;//控制灯灭
				}	

				//判断的关键字符是否为 2"
				//核心数据，即{"switch_led_g":1}中的“1”
				if((g_esp8266_rx_buf[i]==0x32) && (g_esp8266_rx_buf[i+1]==0x22))
				{
					
						//判断控制变量
						if( g_esp8266_rx_buf[i+3]=='1' )
							PFout(10)=0;//控制灯亮
						else
							PFout(10)=1;//控制灯灭
				}

				//判断的关键字符是否为 3"
				//核心数据，即{"switch_led_b":1}中的“1”
				if(g_esp8266_rx_buf[i]==0x33 && g_esp8266_rx_buf[i+1]==0x22)
				{
						//判断控制变量
						if( g_esp8266_rx_buf[i+3]=='1' )
							PEout(13)=0;//控制灯亮
						else
							PEout(13)=1;//控制灯灭
				}				
			}			
#endif
			//清空接收缓冲区、接收计数值、接收结束标志位
			memset((void *)g_esp8266_rx_buf,0,sizeof g_esp8266_rx_buf);
			g_esp8266_rx_cnt=0;
			g_esp8266_rx_end=0;
		}
		
		delay_1ms_cnt++;
		delay_ms(1);
		
		//6秒时间到达
		if((delay_1ms_cnt % 6000) ==0)
		{	
			if(0 == dht11_read(buf))
			{
				g_temp = (float)buf[2]+(float)buf[3]/10;
				g_humi = (float)buf[0]+(float)buf[1]/10;
			}
			
			//上报设备状态
			mqtt_report_devices_status();	
		}
		
		//60秒时间到达
		if((delay_1ms_cnt % 60000) ==0)
		{
			/*	设备端在保活时间间隔内(保护时间在mqtt_connect设置为60s)，至少需要发送一次报文，包括ping请求。
				连接保活时间的取值范围为30秒~1200秒。建议取值300秒以上。
				从物联网平台发送CONNACK响应CONNECT消息时，开始心跳计时。收到PUBLISH、SUBSCRIBE、PING或 PUBACK消息时，会重置计时器。
			*/
			//发送心跳包，过于频繁发送心跳包，服务器将会持续一段时间不发送响应信息[可选]
			rt = mqtt_send_heart();
			
			if(rt == 0)
				CONNECT_MQTT_LED(1);
			else 
				CONNECT_MQTT_LED(0);			
		}		
		
		//按键检测
		if(key_sta_get())
		{
			delay_ms(50);
			
			key_sta=key_sta_get();
			
			if(key_sta & 0x01)
			{
				printf("connect aliyun mqtt\r\n");
				
				//重连阿里云物联网平台
				rt = esp8266_mqtt_init();
				
				if(rt == 0)
					CONNECT_MQTT_LED(1);
				else 
					CONNECT_MQTT_LED(0);
			}

			if(key_sta & 0x02)				
			{
				printf("disconnect aliyun mqtt\r\n");
				
				//断开阿里云物联网平台
				mqtt_disconnect();
				CONNECT_MQTT_LED(0);
			}		
		
		}
	}

}



